//
// Created by root on 2020/4/21.
//

#include <muduo/base/Logging.h>

#include "UserMgr.h"

CUserMgr::CUserMgr() {
    m_pSendMsgThd = new muduo::Thread(std::bind(&CUserMgr::Run, this));
    m_pSendMsgThd->start();
}

CUserMgr::~CUserMgr() {
    delete m_pSendMsgThd;
}

void CUserMgr::Insert(const CUser &_oUser) {
    auto iter = m_hashRegistry.find(_oUser.id());
    if (iter == m_hashRegistry.end())
    {
        m_hashRegistry.insert({_oUser.id(), _oUser});
        m_hashId2Time.insert({_oUser.id(), true});
    }
    else{
        m_hashRegistry[_oUser.id()] = _oUser;
    }
}

CUser CUserMgr::GetUser(const std::string &_sId) {
    auto iter = m_hashRegistry.find(_sId);
    if (iter != m_hashRegistry.end())
    {
        return m_hashRegistry[_sId];
    }
    else{
        return CUser();
    }
}

bool CUserMgr::Delete(const std::string &_sId) {
    auto iter = m_hashRegistry.find(_sId);
    if (iter != m_hashRegistry.end())
    {
        m_hashRegistry.erase(iter);
    }
}

void CUserMgr::CheckRegular() {
    std::unordered_map<std::string, bool> hashId2Time;
    for (auto iter = m_hashId2Time.begin(); iter != m_hashId2Time.end(); iter++)
    {
        if (iter->second)
        {
            iter->second = false;
            hashId2Time.insert(*iter);
        }
        else{
            if (m_hashRegistry.find(iter->first) != m_hashRegistry.end())
            {
                muduo::net::TcpConnectionPtr pTcpConn = m_hashRegistry[iter->first].GetSharedConnPtr();
                if (pTcpConn)
                {
                    LOG_INFO << "shutdown IP:" << pTcpConn->peerAddress().toIpPort() <<
                             " -> "<< pTcpConn->localAddress().toIpPort();
                    pTcpConn->shutdown();
                }
                m_hashRegistry.erase(iter->first);
            }
        }
    }
    m_hashId2Time = hashId2Time;
}

void CUserMgr::UpdateRegular(const std::string &_sName) {
    if (m_hashId2Time.end() != m_hashId2Time.find(_sName))
    {
        m_hashId2Time[_sName] = true;
    }
}

void CUserMgr::Send(const std::string &_sRecieveId, uint64_t _iPacketId, const std::string &_sMessage) {
    std::lock_guard<std::mutex> lock(m_mutexQueue);
    uint64_t iNetByte =  muduo::net::sockets::hostToNetwork64(_iPacketId);  // 本地字节序转换成网络字节序
    std::string sMsgPacket;
    sMsgPacket.append(reinterpret_cast<char*>(&iNetByte), sizeof(iNetByte));
    sMsgPacket.append(_sMessage);
    m_queueSend.push({ _sRecieveId, _sMessage});
}

std::vector<std::string> CUserMgr::GetAllUserName() {
    std::vector<std::string> vtUserNames;
    for (const auto &index : m_hashRegistry)
    {
        vtUserNames.push_back(index.first);
    }
    return vtUserNames;
}

void CUserMgr::Run() {
    while (!m_bExitThd)
    {
        bool bHasMsg = false;
        std::pair<std::string, std::string> pairMsgInfo;
        {
            std::lock_guard<std::mutex> lock(m_mutexQueue);
            if (m_queueSend.size() > 0)
            {
                bHasMsg = true;
                pairMsgInfo = m_queueSend.front();
                m_queueSend.pop();
            }
        }

        if (bHasMsg)
        {
            muduo::net::TcpConnectionPtr pConn = nullptr;
            {
                std::lock_guard<std::mutex> lock(mutexRegistry);
                auto iter = m_hashRegistry.find(pairMsgInfo.first);
                if (iter != m_hashRegistry.end()) {
                    pConn = iter->second.GetSharedConnPtr();
                }
            }

            if (pConn && pConn->connected())
            {
                pConn->send(pairMsgInfo.second);
            }
        }
    }
}

bool CUserMgr::IsValid(const std::string &_sConnId) {
    std::lock_guard<std::mutex> lock(mutexRegistry);
    auto iter = m_hashId2Time.find(_sConnId);
    return iter != m_hashId2Time.end();
}
